home *** CD-ROM | disk | FTP | other *** search
/ Power Hacker 2003 / Power_Hacker_2003.iso / Exploit and vulnerability / w00w00 / sectools / dsniff / remote.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-12-20  |  18.1 KB  |  694 lines

  1. /* -*- Mode:C; tab-width: 8 -*-
  2.  * remote.c --- remote control of Netscape Navigator for Unix.
  3.  * version 1.1.3, for Netscape Navigator 1.1 and newer.
  4.  *
  5.  * Copyright ⌐ 1996 Netscape Communications Corporation, all rights reserved.
  6.  * Created: Jamie Zawinski <jwz@netscape.com>, 24-Dec-94.
  7.  *
  8.  * Permission to use, copy, modify, distribute, and sell this software and its
  9.  * documentation for any purpose is hereby granted without fee, provided that
  10.  * the above copyright notice appear in all copies and that both that
  11.  * copyright notice and this permission notice appear in supporting
  12.  * documentation.  No representations are made about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without express or 
  14.  * implied warranty.
  15.  *
  16.  * To compile:
  17.  *
  18.  *    cc -o netscape-remote remote.c -DSTANDALONE -lXmu -lX11
  19.  *
  20.  * To use:
  21.  *
  22.  *    netscape-remote -help
  23.  *
  24.  * Documentation for the protocol which this code implements may be found at:
  25.  *
  26.  *    http://home.netscape.com/newsref/std/x-remote.html
  27.  *
  28.  * Bugs and commentary to x_cbug@netscape.com.
  29.  */
  30.  
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <unistd.h>
  34. #include <string.h>
  35.  
  36. #include <X11/Xlib.h>
  37. #include <X11/Xatom.h>
  38. #include <X11/Xmu/WinUtil.h>    /* for XmuClientWindow() */
  39.  
  40.  
  41. /* vroot.h is a header file which lets a client get along with `virtual root'
  42.    window managers like swm, tvtwm, olvwm, etc.  If you don't have this header
  43.    file, you can find it at "http://home.netscape.com/newsref/std/vroot.h".
  44.    If you don't care about supporting virtual root window managers, you can
  45.    comment this line out.
  46.  */
  47. #include "vroot.h"
  48.  
  49.  
  50. #ifdef STANDALONE
  51.  static const char *progname = 0;
  52.  static const char *expected_mozilla_version = "1.1";
  53. #else  /* !STANDALONE */
  54.  extern const char *progname;
  55.  extern const char *expected_mozilla_version;
  56. #endif /* !STANDALONE */
  57.  
  58. #define MOZILLA_VERSION_PROP   "_MOZILLA_VERSION"
  59. #define MOZILLA_LOCK_PROP      "_MOZILLA_LOCK"
  60. #define MOZILLA_COMMAND_PROP   "_MOZILLA_COMMAND"
  61. #define MOZILLA_RESPONSE_PROP  "_MOZILLA_RESPONSE"
  62. static Atom XA_MOZILLA_VERSION  = 0;
  63. static Atom XA_MOZILLA_LOCK     = 0;
  64. static Atom XA_MOZILLA_COMMAND  = 0;
  65. static Atom XA_MOZILLA_RESPONSE = 0;
  66.  
  67. static void
  68. mozilla_remote_init_atoms (Display *dpy)
  69. {
  70.   if (! XA_MOZILLA_VERSION)
  71.     XA_MOZILLA_VERSION = XInternAtom (dpy, MOZILLA_VERSION_PROP, False);
  72.   if (! XA_MOZILLA_LOCK)
  73.     XA_MOZILLA_LOCK = XInternAtom (dpy, MOZILLA_LOCK_PROP, False);
  74.   if (! XA_MOZILLA_COMMAND)
  75.     XA_MOZILLA_COMMAND = XInternAtom (dpy, MOZILLA_COMMAND_PROP, False);
  76.   if (! XA_MOZILLA_RESPONSE)
  77.     XA_MOZILLA_RESPONSE = XInternAtom (dpy, MOZILLA_RESPONSE_PROP, False);
  78. }
  79.  
  80. static Window
  81. mozilla_remote_find_window (Display *dpy)
  82. {
  83.   int i;
  84.   Window root = RootWindowOfScreen (DefaultScreenOfDisplay (dpy));
  85.   Window root2, parent, *kids;
  86.   unsigned int nkids;
  87.   Window result = 0;
  88.   Window tenative = 0;
  89.   unsigned char *tenative_version = 0;
  90.  
  91.   if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
  92.     {
  93.       fprintf (stderr, "%s: XQueryTree failed on display %s\n", progname,
  94.            DisplayString (dpy));
  95.       exit (2);
  96.     }
  97.  
  98.   /* root != root2 is possible with virtual root WMs. */
  99.  
  100.   if (! (kids && nkids))
  101.     {
  102.       fprintf (stderr, "%s: root window has no children on display %s\n",
  103.            progname, DisplayString (dpy));
  104.       exit (2);
  105.     }
  106.  
  107.   for (i = nkids-1; i >= 0; i--)
  108.     {
  109.       Atom type;
  110.       int format, status;
  111.       unsigned long nitems, bytesafter;
  112.       unsigned char *version = 0;
  113.       Window w;
  114.  
  115.       w = XmuClientWindow (dpy, kids[i]);
  116.       status = XGetWindowProperty (dpy, w, XA_MOZILLA_VERSION,
  117.                    0, (65536 / sizeof (long)),
  118.                    False, XA_STRING,
  119.                    &type, &format, &nitems, &bytesafter,
  120.                    &version);
  121.       if (! version)
  122.     continue;
  123.       if (strcmp ((char *) version, expected_mozilla_version) &&
  124.       !tenative)
  125.     {
  126.       tenative = w;
  127.       tenative_version = version;
  128.       continue;
  129.     }
  130.       XFree (version);
  131.       if (status == Success && type != None)
  132.     {
  133.       result = w;
  134.       break;
  135.     }
  136.     }
  137.  
  138.   if (result && tenative)
  139.     {
  140.       fprintf (stderr,
  141.            "%s: warning: both version %s (0x%x) and version\n"
  142.            "\t%s (0x%x) are running.  Using version %s.\n",
  143.            progname, tenative_version, (unsigned int) tenative,
  144.            expected_mozilla_version, (unsigned int) result,
  145.            expected_mozilla_version);
  146.       XFree (tenative_version);
  147.       return result;
  148.     }
  149.   else if (tenative)
  150.     {
  151.       fprintf (stderr,
  152.            "%s: warning: expected version %s but found version\n"
  153.            "\t%s (0x%x) instead.\n",
  154.            progname, expected_mozilla_version,
  155.            tenative_version, (unsigned int) tenative);
  156.       XFree (tenative_version);
  157.       return tenative;
  158.     }
  159.   else if (result)
  160.     {
  161.       return result;
  162.     }
  163.   else
  164.     {
  165.       fprintf (stderr, "%s: not running on display %s\n", progname,
  166.            DisplayString (dpy));
  167.       exit (1);
  168.     }
  169. }
  170.  
  171. static void
  172. mozilla_remote_check_window (Display *dpy, Window window)
  173. {
  174.   Atom type;
  175.   int format;
  176.   unsigned long nitems, bytesafter;
  177.   unsigned char *version = 0;
  178.   int status = XGetWindowProperty (dpy, window, XA_MOZILLA_VERSION,
  179.                    0, (65536 / sizeof (long)),
  180.                    False, XA_STRING,
  181.                    &type, &format, &nitems, &bytesafter,
  182.                    &version);
  183.   if (status != Success || !version)
  184.     {
  185.       fprintf (stderr, "%s: window 0x%x is not a Netscape window.\n",
  186.            progname, (unsigned int) window);
  187.       exit (6);
  188.     }
  189.   else if (strcmp ((char *) version, expected_mozilla_version))
  190.     {
  191.       fprintf (stderr,
  192.            "%s: warning: window 0x%x is Netscape version %s;\n"
  193.            "\texpected version %s.\n",
  194.            progname, (unsigned int) window,
  195.            version, expected_mozilla_version);
  196.     }
  197.   XFree (version);
  198. }
  199.  
  200.  
  201. static char *lock_data = 0;
  202.  
  203. static void
  204. mozilla_remote_obtain_lock (Display *dpy, Window window)
  205. {
  206.   Bool locked = False;
  207.   Bool waited = False;
  208.  
  209.   if (! lock_data)
  210.     {
  211.       lock_data = (char *) malloc (255);
  212.       sprintf (lock_data, "pid%d@", getpid ());
  213.       if (gethostname (lock_data + strlen (lock_data), 100))
  214.     {
  215.       perror ("gethostname");
  216.       exit (-1);
  217.     }
  218.     }
  219.  
  220.   do
  221.     {
  222.       int result;
  223.       Atom actual_type;
  224.       int actual_format;
  225.       unsigned long nitems, bytes_after;
  226.       unsigned char *data = 0;
  227.  
  228.       XGrabServer (dpy);   /* ################################# DANGER! */
  229.  
  230.       result = XGetWindowProperty (dpy, window, XA_MOZILLA_LOCK,
  231.                    0, (65536 / sizeof (long)),
  232.                    False, /* don't delete */
  233.                    XA_STRING,
  234.                    &actual_type, &actual_format,
  235.                    &nitems, &bytes_after,
  236.                    &data);
  237.       if (result != Success || actual_type == None)
  238.     {
  239.       /* It's not now locked - lock it. */
  240. #ifdef DEBUG_PROPS
  241.       fprintf (stderr, "%s: (writing " MOZILLA_LOCK_PROP
  242.            " \"%s\" to 0x%x)\n",
  243.            progname, lock_data, (unsigned int) window);
  244. #endif
  245.       XChangeProperty (dpy, window, XA_MOZILLA_LOCK, XA_STRING, 8,
  246.                PropModeReplace, (unsigned char *) lock_data,
  247.                strlen (lock_data));
  248.       locked = True;
  249.     }
  250.  
  251.       XUngrabServer (dpy); /* ################################# danger over */
  252.       XSync (dpy, False);
  253.  
  254.       if (! locked)
  255.     {
  256.       /* We tried to grab the lock this time, and failed because someone
  257.          else is holding it already.  So, wait for a PropertyDelete event
  258.          to come in, and try again. */
  259.  
  260.       fprintf (stderr, "%s: window 0x%x is locked by %s; waiting...\n",
  261.            progname, (unsigned int) window, data);
  262.       waited = True;
  263.  
  264.       while (1)
  265.         {
  266.           XEvent event;
  267.           XNextEvent (dpy, &event);
  268.           if (event.xany.type == DestroyNotify &&
  269.           event.xdestroywindow.window == window)
  270.         {
  271.           fprintf (stderr, "%s: window 0x%x unexpectedly destroyed.\n",
  272.                progname, (unsigned int) window);
  273.           exit (6);
  274.         }
  275.           else if (event.xany.type == PropertyNotify &&
  276.                event.xproperty.state == PropertyDelete &&
  277.                event.xproperty.window == window &&
  278.                event.xproperty.atom == XA_MOZILLA_LOCK)
  279.         {
  280.           /* Ok!  Someone deleted their lock, so now we can try
  281.              again. */
  282. #ifdef DEBUG_PROPS
  283.           fprintf (stderr, "%s: (0x%x unlocked, trying again...)\n",
  284.                progname, (unsigned int) window);
  285. #endif
  286.           break;
  287.         }
  288.         }
  289.     }
  290.       if (data)
  291.     XFree (data);
  292.     }
  293.   while (! locked);
  294.  
  295.   if (waited)
  296.     fprintf (stderr, "%s: obtained lock.\n", progname);
  297. }
  298.  
  299.  
  300. static void
  301. mozilla_remote_free_lock (Display *dpy, Window window)
  302. {
  303.   int result;
  304.   Atom actual_type;
  305.   int actual_format;
  306.   unsigned long nitems, bytes_after;
  307.   unsigned char *data = 0;
  308.  
  309. #ifdef DEBUG_PROPS
  310.       fprintf (stderr, "%s: (deleting " MOZILLA_LOCK_PROP
  311.            " \"%s\" from 0x%x)\n",
  312.            progname, lock_data, (unsigned int) window);
  313. #endif
  314.  
  315.   result = XGetWindowProperty (dpy, window, XA_MOZILLA_LOCK,
  316.                    0, (65536 / sizeof (long)),
  317.                    True, /* atomic delete after */
  318.                    XA_STRING,
  319.                    &actual_type, &actual_format,
  320.                    &nitems, &bytes_after,
  321.                    &data);
  322.   if (result != Success)
  323.     {
  324.       fprintf (stderr, "%s: unable to read and delete " MOZILLA_LOCK_PROP
  325.            " property\n",
  326.            progname);
  327.       return;
  328.     }
  329.   else if (!data || !*data)
  330.     {
  331.       fprintf (stderr, "%s: invalid data on " MOZILLA_LOCK_PROP
  332.            " of window 0x%x.\n",
  333.            progname, (unsigned int) window);
  334.       return;
  335.     }
  336.   else if (strcmp ((char *) data, lock_data))
  337.     {
  338.       fprintf (stderr, "%s: " MOZILLA_LOCK_PROP
  339.            " was stolen!  Expected \"%s\", saw \"%s\"!\n",
  340.            progname, lock_data, data);
  341.       return;
  342.     }
  343.  
  344.   if (data)
  345.     XFree (data);
  346. }
  347.  
  348.  
  349. static int
  350. mozilla_remote_command (Display *dpy, Window window, const char *command,
  351.             Bool raise_p)
  352. {
  353.   int result = 0;
  354.   Bool done = False;
  355.   char *new_command = 0;
  356.  
  357.   /* The -noraise option is implemented by passing a "noraise" argument
  358.      to each command to which it should apply.
  359.    */
  360.   if (! raise_p)
  361.     {
  362.       char *close;
  363.       new_command = (char *) malloc (strlen (command) + 20);
  364.       strcpy (new_command, command);
  365.       close = strrchr (new_command, ')');
  366.       if (close)
  367.     strcpy (close, ", noraise)");
  368.       else
  369.     strcat (new_command, "(noraise)");
  370.       command = new_command;
  371.     }
  372.  
  373. #ifdef DEBUG_PROPS
  374.   fprintf (stderr, "%s: (writing " MOZILLA_COMMAND_PROP " \"%s\" to 0x%x)\n",
  375.        progname, command, (unsigned int) window);
  376. #endif
  377.  
  378.   XChangeProperty (dpy, window, XA_MOZILLA_COMMAND, XA_STRING, 8,
  379.            PropModeReplace, (unsigned char *) command,
  380.            strlen (command));
  381.  
  382.   while (!done)
  383.     {
  384.       XEvent event;
  385.       XNextEvent (dpy, &event);
  386.       if (event.xany.type == DestroyNotify &&
  387.       event.xdestroywindow.window == window)
  388.     {
  389.       /* Print to warn user...*/
  390.       fprintf (stderr, "%s: window 0x%x was destroyed.\n",
  391.            progname, (unsigned int) window);
  392.       result = 6;
  393.       goto DONE;
  394.     }
  395.       else if (event.xany.type == PropertyNotify &&
  396.            event.xproperty.state == PropertyNewValue &&
  397.            event.xproperty.window == window &&
  398.            event.xproperty.atom == XA_MOZILLA_RESPONSE)
  399.     {
  400.       Atom actual_type;
  401.       int actual_format;
  402.       unsigned long nitems, bytes_after;
  403.       unsigned char *data = 0;
  404.  
  405.       result = XGetWindowProperty (dpy, window, XA_MOZILLA_RESPONSE,
  406.                        0, (65536 / sizeof (long)),
  407.                        True, /* atomic delete after */
  408.                        XA_STRING,
  409.                        &actual_type, &actual_format,
  410.                        &nitems, &bytes_after,
  411.                        &data);
  412. #ifdef DEBUG_PROPS
  413.       if (result == Success && data && *data)
  414.         {
  415.           fprintf (stderr, "%s: (server sent " MOZILLA_RESPONSE_PROP
  416.                " \"%s\" to 0x%x.)\n",
  417.                progname, data, (unsigned int) window);
  418.         }
  419. #endif
  420.  
  421.       if (result != Success)
  422.         {
  423.           fprintf (stderr, "%s: failed reading " MOZILLA_RESPONSE_PROP
  424.                " from window 0x%0x.\n",
  425.                progname, (unsigned int) window);
  426.           result = 6;
  427.           done = True;
  428.         }
  429.       else if (!data || strlen((char *) data) < 5)
  430.         {
  431.           fprintf (stderr, "%s: invalid data on " MOZILLA_RESPONSE_PROP
  432.                " property of window 0x%0x.\n",
  433.                progname, (unsigned int) window);
  434.           result = 6;
  435.           done = True;
  436.         }
  437.       else if (*data == '1')    /* positive preliminary reply */
  438.         {
  439.           fprintf (stderr, "%s: %s\n", progname, data + 4);
  440.           /* keep going */
  441.           done = False;
  442.         }
  443. #if 1
  444.       else if (!strncmp ((char *)data, "200", 3)) /* positive completion */
  445.         {
  446.           result = 0;
  447.           done = True;
  448.         }
  449. #endif
  450.       else if (*data == '2')        /* positive completion */
  451.         {
  452.           fprintf (stderr, "%s: %s\n", progname, data + 4);
  453.           result = 0;
  454.           done = True;
  455.         }
  456.       else if (*data == '3')    /* positive intermediate reply */
  457.         {
  458.           fprintf (stderr, "%s: internal error: "
  459.                "server wants more information?  (%s)\n",
  460.                progname, data);
  461.           result = 3;
  462.           done = True;
  463.         }
  464.       else if (*data == '4' ||    /* transient negative completion */
  465.            *data == '5')    /* permanent negative completion */
  466.         {
  467.           fprintf (stderr, "%s: %s\n", progname, data + 4);
  468.           result = (*data - '0');
  469.           done = True;
  470.         }
  471.       else
  472.         {
  473.           fprintf (stderr,
  474.                "%s: unrecognised " MOZILLA_RESPONSE_PROP
  475.                " from window 0x%x: %s\n",
  476.                progname, (unsigned int) window, data);
  477.           result = 6;
  478.           done = True;
  479.         }
  480.  
  481.       if (data)
  482.         XFree (data);
  483.     }
  484. #ifdef DEBUG_PROPS
  485.       else if (event.xany.type == PropertyNotify &&
  486.            event.xproperty.window == window &&
  487.            event.xproperty.state == PropertyDelete &&
  488.            event.xproperty.atom == XA_MOZILLA_COMMAND)
  489.     {
  490.       fprintf (stderr, "%s: (server 0x%x has accepted "
  491.            MOZILLA_COMMAND_PROP ".)\n",
  492.            progname, (unsigned int) window);
  493.     }
  494. #endif /* DEBUG_PROPS */
  495.     }
  496.  
  497.  DONE:
  498.  
  499.   if (new_command)
  500.     free (new_command);
  501.  
  502.   return result;
  503. }
  504.  
  505. int
  506. mozilla_remote_commands (Display *dpy, Window window, char **commands)
  507. {
  508.   Bool raise_p = True;
  509.   int status = 0;
  510.   mozilla_remote_init_atoms (dpy);
  511.  
  512.   if (window == 0)
  513.     window = mozilla_remote_find_window (dpy);
  514.   else
  515.     mozilla_remote_check_window (dpy, window);
  516.  
  517.   XSelectInput (dpy, window, (PropertyChangeMask|StructureNotifyMask));
  518.  
  519.   mozilla_remote_obtain_lock (dpy, window);
  520.  
  521.   while (*commands)
  522.     {
  523.       if (!strcmp (*commands, "-raise"))
  524.     raise_p = True;
  525.       else if (!strcmp (*commands, "-noraise"))
  526.     raise_p = False;
  527.       else
  528.     status = mozilla_remote_command (dpy, window, *commands, raise_p);
  529.  
  530.       if (status != 0)
  531.     break;
  532.       commands++;
  533.     }
  534.  
  535.   /* When status = 6, it means the window has been destroyed */
  536.   /* It is invalid to free the lock when window is destroyed. */
  537.  
  538.   if ( status != 6 )
  539.   mozilla_remote_free_lock (dpy, window);
  540.  
  541.   return status;
  542. }
  543.  
  544.  
  545. #ifdef STANDALONE
  546.  
  547. static void
  548. usage (void)
  549. {
  550.   fprintf (stderr, "usage: %s [ options ... ]\n\
  551.        where options include:\n\
  552. \n\
  553.        -help                     to show this message.\n\
  554.        -display <dpy>            to specify the X server to use.\n\
  555.        -remote <remote-command>  to execute a command in an already-running\n\
  556.                                  Netscape process.  See the manual for a\n\
  557.                                  list of valid commands.\n\
  558.        -id <window-id>           the id of an X window to which the -remote\n\
  559.                                  commands should be sent; if unspecified,\n\
  560.                                  the first window found will be used.\n\
  561.        -raise                    whether following -remote commands should\n\
  562.                                  cause the window to raise itself to the top\n\
  563.                                  (this is the default.)\n\
  564.        -noraise                  the opposite of -raise: following -remote\n\
  565.                                  commands will not auto-raise the window.\n\
  566. ",
  567.        progname);
  568. }
  569.  
  570.  
  571. void
  572. main (int argc, char **argv)
  573. {
  574.   Display *dpy;
  575.   char *dpy_string = 0;
  576.   char **remote_commands = 0;
  577.   int remote_command_count = 0;
  578.   int remote_command_size = 0;
  579.   unsigned long remote_window = 0;
  580.   Bool sync_p = False;
  581.   int i;
  582.  
  583.   progname = strrchr (argv[0], '/');
  584.   if (progname)
  585.     progname++;
  586.   else
  587.     progname = argv[0];
  588.  
  589.   /* Hack the -help and -version arguments before opening the display. */
  590.   for (i = 1; i < argc; i++)
  591.     {
  592.       if (!strcasecmp (argv [i], "-h") ||
  593.       !strcasecmp (argv [i], "-help"))
  594.     {
  595.       usage ();
  596.       exit (0);
  597.     }
  598.       else if (!strcmp (argv [i], "-d") ||
  599.            !strcmp (argv [i], "-dpy") ||
  600.            !strcmp (argv [i], "-disp") ||
  601.            !strcmp (argv [i], "-display"))
  602.     {
  603.       i++;
  604.       dpy_string = argv [i];
  605.     }
  606.       else if (!strcmp (argv [i], "-sync") ||
  607.            !strcmp (argv [i], "-synchronize"))
  608.     {
  609.       sync_p = True;
  610.     }
  611.       else if (!strcmp (argv [i], "-remote"))
  612.     {
  613.       if (remote_command_count == remote_command_size)
  614.         {
  615.           remote_command_size += 20;
  616.           remote_commands =
  617.         (remote_commands
  618.          ? realloc (remote_commands,
  619.                 remote_command_size * sizeof (char *))
  620.          : calloc (remote_command_size, sizeof (char *)));
  621.         }
  622.       i++;
  623.       if (!argv[i] || *argv[i] == '-' || *argv[i] == 0)
  624.         {
  625.           fprintf (stderr, "%s: invalid `-remote' option \"%s\"\n",
  626.                progname, argv[i] ? argv[i] : "");
  627.           usage ();
  628.           exit (-1);
  629.         }
  630.       remote_commands [remote_command_count++] = argv[i];
  631.     }
  632.       else if (!strcmp (argv [i], "-raise") ||
  633.            !strcmp (argv [i], "-noraise"))
  634.     {
  635.       char *r = argv [i];
  636.       if (remote_command_count == remote_command_size)
  637.         {
  638.           remote_command_size += 20;
  639.           remote_commands =
  640.         (remote_commands
  641.          ? realloc (remote_commands,
  642.                 remote_command_size * sizeof (char *))
  643.          : calloc (remote_command_size, sizeof (char *)));
  644.         }
  645.       remote_commands [remote_command_count++] = r;
  646.     }
  647.       else if (!strcmp (argv [i], "-id"))
  648.     {
  649.       char c;
  650.       if (remote_command_count > 0)
  651.         {
  652.           fprintf (stderr,
  653.         "%s: the `-id' option must preceed all `-remote' options.\n",
  654.                progname);
  655.           usage ();
  656.           exit (-1);
  657.         }
  658.       else if (remote_window != 0)
  659.         {
  660.           fprintf (stderr, "%s: only one `-id' option may be used.\n",
  661.                progname);
  662.           usage ();
  663.           exit (-1);
  664.         }
  665.       i++;
  666.       if (argv[i] &&
  667.           1 == sscanf (argv[i], " %ld %c", &remote_window, &c))
  668.         ;
  669.       else if (argv[i] &&
  670.            1 == sscanf (argv[i], " 0x%lx %c", &remote_window, &c))
  671.         ;
  672.       else
  673.         {
  674.           fprintf (stderr, "%s: invalid `-id' option \"%s\"\n",
  675.                progname, argv[i] ? argv[i] : "");
  676.           usage ();
  677.           exit (-1);
  678.         }
  679.     }
  680.     }
  681.  
  682.   dpy = XOpenDisplay (dpy_string);
  683.   if (! dpy)
  684.     exit (-1);
  685.  
  686.   if (sync_p)
  687.     XSynchronize (dpy, True);
  688.  
  689.   exit (mozilla_remote_commands (dpy, (Window) remote_window,
  690.                  remote_commands));
  691. }
  692.  
  693. #endif /* STANDALONE */
  694.